#include "device/ec200/AtNetworkMqttClientEC200.h"

#define PUBLISH_CMD "AT+QMTPUBEX=%d,0,0,0,\"%s\",%d\r\n" // 发布数据指令
#define PUBLISH_START ">"                                // 发布数据-发送数据标识符

#define SUBSCRIBE_CMD "AT+QMTSUB=%d,1,\"%s\",%d\r\n" // 订阅主题指令
#define UNSUBSCRIBE_CMD "AT+QMTUNS=%d,2,\"%s\"\r\n"  // 取消订阅指令

#define ISCONNECTED_CMD "AT+QMTCONN?" // 判断MQTT是否连接

#define DICONNECT_CMD1 "AT+QMTDISC=%d\r\n"  // 注销MQTT连接指令
#define DICONNECT_CMD2 "AT+QMTCLOSE=%d\r\n" // 断开MQTT连接指令

#define CONNECT_CFG1 "AT+QMTCFG=\"version\",%d,4\r\n"     // MQTT配置-指令1
#define CONNECT_CFG2 "AT+QMTCFG=\"recv/mode\",%d,0,1\r\n" // MQTT配置-指令2
#define CONNECT_CFG3 "AT+QMTCFG=\"keepalive\",%d,120\r\n" // MQTT配置-指令3

#define CONNECT_CMD1 "AT+QMTOPEN=%d,\"%s\",%d\r\n"            // 打开MQTT连接
#define CONNECT_CMD2 "AT+QMTCONN=%d,\"%s\",\"%s\",\"%s\"\r\n" // 注册MQTT连接

// +QMTRECV: <client_idx>,<msgid>,<topic>[,<payload_len>],<payload>
// +QMTSTAT: <client_idx>,<err_code>
AtNetworkMqttClientEC200::AtNetworkMqttClientEC200(AtNetworkDevice *device, uint16_t cid) {
  this->clientId = (GSM_STRING)MEM_ALLOC(MQTT_CLIENTID_SIZE);
  this->username = (GSM_STRING)MEM_ALLOC(MQTT_USERNAME_SIZE);
  this->password = (GSM_STRING)MEM_ALLOC(MQTT_PASSWORD_SIZE);
  this->host = (GSM_STRING)MEM_ALLOC(MQTT_HOST_SIZE);

  this->route = new AtNetworkMqttRouteEC200(this, device);
  this->state = new AtNetworkMqttStateEC200(this, device);

  sprintf(this->route->urcCmd, "+QMTRECV: %d,", cid);
  sprintf(this->state->urcCmd, "+QMTSTAT: %d,", cid);

  memset(this->clientId, 0, MQTT_CLIENTID_SIZE);
  memset(this->username, 0, MQTT_USERNAME_SIZE);
  memset(this->password, 0, MQTT_PASSWORD_SIZE);
  memset(this->host, 0, MQTT_HOST_SIZE);

  this->device = device;
  this->port = 1883;
  this->cid = cid;
}

AtNetworkMqttClientEC200::~AtNetworkMqttClientEC200() {
  delete this->route;
  delete this->state;

  free(this->clientId);
  free(this->username);
  free(this->password);
  free(this->host);
};

/**
 * 发布数据
 */
bool AtNetworkMqttClientEC200::publish(const char *topic, char *body, size_t length) {
  this->device->streamPrintfClear(PUBLISH_CMD, this->cid, topic, length);
  if (this->device->wait(PUBLISH_START) == AT_RCODE1) {
    this->device->streamWriteClear(body, GSM_NL);
  } else {
    return false;
  }

  if (this->device->wait(AT_OK) != AT_RCODE1) {
    return false;
  }

  return true;
}

/**
 * 订阅主题
 */
bool AtNetworkMqttClientEC200::subscribe(AtNetworkMqttTopic *topic, uint8_t qos) {
  this->device->streamPrintfClear(SUBSCRIBE_CMD, this->cid, topic->topic, qos);
  if (this->device->wait(5000, AT_OK) == AT_RCODE1) {
    return this->route->subscribe(topic);
  }

  return false;
}

/**
 * 取消订阅主题
 */
bool AtNetworkMqttClientEC200::unsubscribe(AtNetworkMqttTopic *topic) {
  this->device->streamPrintfClear(UNSUBSCRIBE_CMD, this->cid, topic->topic);
  if (this->device->wait(5000, AT_OK) == AT_RCODE1) {
    return this->route->unsubscribe(topic);
  }

  return false;
}

/**
 * 判定当前MQTT服务是否连接成功(+QMTCONN: <client_idx>,<state>)
 */
bool AtNetworkMqttClientEC200::isConnected(uint32_t timeout) {
  this->device->streamWriteClear(ISCONNECTED_CMD GSM_NL);
  if (this->device->wait("+QMTCONN: ") == AT_RCODE1) {
    return true;
  }
  if (this->device->streamGetInt(1, ',') != this->cid) {
    return false;
  }
  if (this->device->streamGetInt(1) != 3) {
    return false;
  }

  return false;
}

/**
 * 断开连接
 * @param timeout 超时时长
 */
bool AtNetworkMqttClientEC200::diconnect(uint32_t timeout) {
  // 关闭MQTT服务连接-----------------------------------------
  this->device->streamPrintfClear(DICONNECT_CMD1, this->cid);
  if (this->device->wait(30000, AT_OK) != AT_RCODE1) {
    return false;
  }

  // 关闭MQTT网络连接-----------------------------------------
  this->device->streamPrintfClear(DICONNECT_CMD2, this->cid);
  if (this->device->wait(30000, AT_OK) != AT_RCODE1) {
    return false;
  }

  // 销毁URC监听---------------------------------------------
  this->device->remove_urc_callback(this->route);
  this->device->remove_urc_callback(this->state);

  return true;
}

/**
 * 初始化MQTT服务
 * @param timeout 超时时长
 */
bool AtNetworkMqttClientEC200::connect(uint32_t timeout) {
  // MQTT 通道配置----------------------------------------------------------------
  this->device->streamPrintfClear(CONNECT_CFG1, this->cid);
  this->device->streamPrintfClear(CONNECT_CFG2, this->cid);
  this->device->streamPrintfClear(CONNECT_CFG3, this->cid);

  // 打开MQTT连接(+QMTOPEN: <client_idx>,<result>)--------------------------------
  this->device->streamPrintfClear(CONNECT_CMD1, this->cid, this->host, this->port);
  if (this->device->wait(30000, "+QMTOPEN: ") != AT_RCODE1) {
    return false;
  }
  if (this->device->streamGetInt(1, ',') != this->cid) {
    return false;
  }
  if (this->device->streamGetInt(1) != 0) {
    return false;
  }

  // 初始化MQTT连接(+QMTCONN: <client_idx>,<state>)------------------------------
  this->device->streamPrintfClear(CONNECT_CMD2, this->cid, this->clientId,
                                  this->username, this->password);
  if (this->device->wait(30000, "+QMTCONN: ") != AT_RCODE1) {
    return false;
  }
  if (this->device->streamGetInt(1) != this->cid) {
    return false;
  }

  // 初始化MQTT所需的URC配置----------------------------------------------------
  this->device->add_urc_callback(this->route);
  this->device->add_urc_callback(this->state);

  // 等待MQTT连接成功----------------------------------------------------------
  uint32_t expire_time = millis() + timeout * 10;
  while (timeout > 0 && expire_time > millis()) {
    if (this->isConnected(timeout)) {
      return true;
    }

    delay(500);
  }

  return false;
}